#include "include/currentitemobserver.h"

#include "include/treeitem.h"
#include "include/htmledit.h" //to be removed
#include "include/RichText.h"
#include <QUrl>
#include <QTextFragment>
#include <QTextCharFormat>
#include <QTextImageFormat>
#include <QRegExp>

#include <iostream>


namespace
{

//	QString appendImage(QString html, QString imageResourceName)
//	{
//		return RichText::appendImage(html, imageResourceName);
//		//return html + QString("<br/><img src=\"%0\" alt=\"Image\" />").arg(imageResourceName);
//	}

	QString buildImageTag(QString imageResourceName)
	{
		return RichText::buildImageTag(imageResourceName);
	}


	void toDocument(QTextDocument* dest, TreeItem* src, TreeItem::DataColumn col, const QString& imageResourceName)
	{
		//dest->setDefaultStyleSheet("p { font-size: 12pt; font-weight: bold; margin: 0; } ");

		dest->clear();

		QString plainText = src->getText(col);

		QString html = RichText::formatToHTML(plainText.replace("\n", "<br/>"));

		if (src->hasImage(col))
		{
			dest->addResource(QTextDocument::ImageResource, QUrl(imageResourceName), src->image(col));
			QString imageTag = buildImageTag(imageResourceName);
			html += (!plainText.isEmpty() ? "<br/><br/>" : "") + imageTag;
		}

		html = "<html><body><p>" + html + "</p></body></html>";

		dest->setHtml(html);

		RichText::alignAllText(dest, Qt::AlignHCenter);
	}


	void toDocument(QTextDocument* dest, TreeModel* model, QModelIndex index, const QString& imageResourceName)
	{
		toDocument(dest, model->getItem(index), (TreeItem::DataColumn)index.column(), imageResourceName);
	}


	bool containsImage(QTextDocument* pDoc, const QString& imageResourceName)
	{
		//checking that document text contains reference to given image resource

		for (QTextBlock it = pDoc->begin(); it != pDoc->end(); it = it.next())
		{
			for (QTextBlock::iterator it2 = it.begin(); it2 != it.end(); ++it2)
			{
				QTextFragment fragment = it2.fragment();
				if (fragment.charFormat().isImageFormat())
				{
					QTextImageFormat fmt = fragment.charFormat().toImageFormat();
					if (fmt.name() == imageResourceName)
						return true;
				}
			}
		}

		return false;
	}


	QImage getImage(QTextDocument *pDoc, const QString& imageResourceName)
	{
		QVariant v = pDoc->resource(QTextDocument::ImageResource, imageResourceName);
		return v.isValid() ? v.value<QImage>() : QImage();
	}


	void toModel(TreeModel* dest, QTextDocument* src, QUuid itemUuid, TreeItem::DataColumn col, const QString& imageResourceName)
	{
		TreeItem* pTi = dest->getItemByUuid(itemUuid);
		if (pTi == 0)
			return;

		QString plainText = src->toPlainText()
				.remove(QChar::ObjectReplacementCharacter)
				.remove(QRegExp("[ ,\n,\t,\r]+$"));

		pTi->setText(col, plainText);

		if (containsImage(src, imageResourceName))
			pTi->setImage(col, getImage(src, imageResourceName));
		else
			pTi->resetImage(col);

		//NOTE: notifying irrespectively wheter changes have really had place
		//this could be improved but it would require to compare images and multimedia types (which will be added in future)
		dest->notifyItemUpdate(pTi);
	}

} //private namespace


CurrentItemObserver::CurrentItemObserver(QObject *parent) :
	QObject(parent),
	m_pModel(0),
	m_pSelectionModel(0),
	m_pQuestion(new QTextDocument(this)),
	m_pAnswer(new QTextDocument(this))
{
}



QString CurrentItemObserver::imageResourceName() const
{
	return m_imageResourceName;
}


void  CurrentItemObserver::setImageResourceName(const QString& value)
{
	m_imageResourceName = value;
}


QTextDocument* CurrentItemObserver::question() const
{
	return m_pQuestion;
}


QTextDocument* CurrentItemObserver::answer() const
{
	return m_pAnswer;
}


void CurrentItemObserver::bindTo(TreeModel* pModel, QItemSelectionModel* pSelectionModel)
{
	m_pModel = pModel;
	m_pSelectionModel = pSelectionModel;

	if (m_pModel != 0 && m_pSelectionModel != 0)
	{
		QModelIndex current = m_pSelectionModel->currentIndex();

		TreeItem* pTi = m_pModel->getItem(current);
		if (pTi != 0)
			m_currentItemUuid = pTi->getUuid();
		else
			m_currentItemUuid = QUuid();

		connect(m_pModel, SIGNAL(treeItemChanged(const TreeItem&)), this, SLOT(onModelTreeItemChanged(const TreeItem&)));

		connect(m_pSelectionModel,
		        SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
		        this,
		        SLOT(onCurrentChanged(const QModelIndex&, const QModelIndex&)));

		connect(m_pModel, SIGNAL(newTreeCreated()), this, SLOT(onNewTreeCreated()));

		updateFields(current);
	}
}


void CurrentItemObserver::onCurrentChanged(const QModelIndex &current, const QModelIndex &)
{
	TreeItem* pTi = m_pModel->getItem(current);
	if (pTi != 0)
		m_currentItemUuid = pTi->getUuid();
	else
		m_currentItemUuid = QUuid();

	updateFields(current);
}


void CurrentItemObserver::onModelTreeItemChanged(const TreeItem& item)
{
	if (item.getUuid() != m_currentItemUuid)
		return;

	QModelIndex current = m_pSelectionModel->currentIndex();

	updateFields(current);
}


void CurrentItemObserver::updateFields(const QModelIndex& current)
{
	if (current.isValid())
	{
		toDocument(m_pQuestion, m_pModel, m_pModel->index(current.row(), TreeItem::QuestionColumn, current.parent()), imageResourceName());
		toDocument(m_pAnswer, m_pModel, m_pModel->index(current.row(), TreeItem::AnswerColumn, current.parent()), imageResourceName());
	}
	else
	{
		m_pQuestion->clear();
		m_pAnswer->clear();
	}

	emit questionChanged(m_pQuestion);
	emit answerChanged(m_pAnswer);
}


void  CurrentItemObserver::questionToModel()
{
	toModel(m_pModel, m_pQuestion, m_currentItemUuid, TreeItem::QuestionColumn, imageResourceName());
}


void CurrentItemObserver::answerToModel()
{
	toModel(m_pModel, m_pAnswer, m_currentItemUuid, TreeItem::AnswerColumn, imageResourceName());
}


void CurrentItemObserver::onNewTreeCreated()
{
	m_pQuestion->clear();
	m_pAnswer->clear();
}


QFont CurrentItemObserver::defaultFont() const
{
	return m_defaultFont;
}


void CurrentItemObserver::setDefaultFont(QFont font)
{
	m_defaultFont = font;
	m_pQuestion->setDefaultFont(font);
	m_pAnswer->setDefaultFont(font);
}



